package com.kongge.viewdisplayframeworklib.ui.view.viewscroller;

import java.util.HashMap;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;

import com.kongge.viewdisplayframeworklib.R;


/**
 * The AndroidViewScroller is a wide area with a finite number of screens. Each screen contains a ViewGroup. An
 * AndroidViewScroller is meant to be used with a fixed width only.
 */
public class ViewScroller extends ViewGroup {

    private final static String        TAG                     = "ViewGroup";

    private static final int           INVALID_SCREEN          = -1;
    private static final int           DURATION_BETWEEN_SCREEN = 500;
    protected static final int         TOUCH_MOVE_DISTANCE = 20; // 点击和滑动事件的灵敏度
    /**
     * The velocity at which a fling gesture will cause us to snap to the next screen
     */
    private static final int           SNAP_VELOCITY           = 1000;
    private int                        mDefaultScreen;
    private boolean                    mFirstLayout            = true;
    protected int                      mCurrentScreen;
    protected int                      mNextScreen             = INVALID_SCREEN;
    protected Scroller                 mScroller;
    protected VelocityTracker          mVelocityTracker;
    protected float                    mLastMotionX;
    protected float                    mLastMotionY;
    protected final static int         TOUCH_STATE_REST        = 0;
    protected final static int         TOUCH_STATE_SCROLLING   = 1;
    protected int                      mTouchState             = TOUCH_STATE_REST;

    private OnViewChangeListener      mViewChangeListener;

    private OnBarChangeVisibleListener mBarChangeVisibleListener;

    private OnPageChangeByScroll       mOnPageChangeByScroll;
    private boolean                    mAllowLongPress;
    protected boolean                  mLocked;
    protected boolean mLockScroll = false; // 只禁止滑动切换，而不是消费所有的滑动事件
    protected boolean                  mCycleShowed;
    protected boolean				   canMoveInBoundry;
    private boolean                    isAbleMoveToLeft        = true;
    private boolean                    isAbleMoveToRight       = true;
    protected boolean                  hasNavibar			   = false;
    protected int                      mTouchSlop;
    final Rect                         mDrawerBounds           = new Rect();
    final Rect                         mClipBounds             = new Rect();
    int                                mDrawerContentHeight;
    int                                mDrawerContentWidth;
    // Bitmap bitMapBuffer = null;
    // 页面指示器
    protected PageIndex                  pageIndex               = null;
    private HashMap<View, Integer>     viewIndexMap            = new HashMap<View, Integer>();

    protected boolean                    drawPageIndex           = true;                        // 是否绘画页面下面的标记index的点(默认绘画)
    private InterceptTouchListener     mInterceptTouchListener = null;                        // 需要自己处理touchEvent事件的子组件
    
    public ViewScroller(Context context) {
        this(context, null);
    }

    /**
     * Used to inflate the Workspace from XML.
     * 
     * @param context The application's context.
     * @param attrs The attribtues set containing the Workspace's customization values.
     */
    public ViewScroller(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * Used to inflate the Workspace from XML.
     * 
     * @param context The application's context.
     * @param attrs The attribtues set containing the Workspace's customization values.
     * @param defStyle Unused.
     */
    public ViewScroller(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewScroller, defStyle, 0);
        mDefaultScreen = a.getInt(R.styleable.ViewScroller_defaultScreen, 0);
        drawPageIndex = a.getBoolean(R.styleable.ViewScroller_drawPageIndex, true);
        canMoveInBoundry = a.getBoolean(R.styleable.ViewScroller_canMoveInBoundry, false);
        hasNavibar = a.getBoolean(R.styleable.ViewScroller_hasNavibar, false);
        a.recycle();
        mHandler = new GestureHandler();
    }

    /**
     * Initializes various states for this workspace.
     */
    public void initWorkspace(int defaultScreen) {
        mScroller = new Scroller(getContext());
        defaultScreen  = Math.max(0, Math.min(defaultScreen, getChildCount() - 1));
        mDefaultScreen = defaultScreen;
        mCurrentScreen = defaultScreen;
        // viewChanged(mCurrentScreen);
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    }

    @Override
    public void addView(View child, int index, LayoutParams params) {
        if (!(child instanceof ViewGroup)) {
            throw new IllegalArgumentException("A Workspace can only have ViewGroup children.");
        }
        super.addView(child, index, params);
    }

    @Override
    public void addView(View child) {
        if (!(child instanceof ViewGroup)) {
            throw new IllegalArgumentException("A Workspace can only have ViewGroup children.");
        }
        super.addView(child);
    }

    @Override
    public void addView(View child, int index) {
        if (!(child instanceof ViewGroup)) {
            throw new IllegalArgumentException("A Workspace can only have ViewGroup children.");
        }
        super.addView(child, index);
    }

    @Override
    public void addView(View child, int width, int height) {
        if (!(child instanceof ViewGroup)) {
            throw new IllegalArgumentException("A Workspace can only have ViewGroup children.");
        }
        super.addView(child, width, height);
    }

    @Override
    public void addView(View child, LayoutParams params) {
        if (!(child instanceof ViewGroup)) {
            throw new IllegalArgumentException("A Workspace can only have ViewGroup children.");
        }
        super.addView(child, params);
    }

    public boolean isAbleMoveToLeft() {
        return isAbleMoveToLeft;
    }

    public void setAbleMoveToLeft(boolean isAbleMoveToLeft) {
        this.isAbleMoveToLeft = isAbleMoveToLeft;
    }

    public boolean isAbleMoveToRight() {
        return isAbleMoveToRight;
    }

    public void setAbleMoveToRight(boolean isAbleMoveToRight) {
        this.isAbleMoveToRight = isAbleMoveToRight;
    }

    /**
     * Returns the index of the currently displayed screen.
     * 
     * @return The index of the currently displayed screen.
     */
    private int getCurrentScreen() {
        return mCurrentScreen;
    }

    /**
     * Sets the current screen.
     * 
     * @param currentScreen
     */
    private void setCurrentScreen(int currentScreen) {
        int oldIndex = mCurrentScreen;
        currentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
        View focusedChild = getFocusedChild();
        boolean changingScreens = currentScreen != mCurrentScreen;
        if (focusedChild != null && changingScreens && focusedChild == getChildAt(mCurrentScreen)) {
            focusedChild.clearFocus();
        }

        mCurrentScreen = currentScreen;
        scrollTo(mCurrentScreen * this.getWindowWidth(), 0);
        invalidate();

        notifyTabShouldChange(mCurrentScreen);
        viewChanged(oldIndex, mCurrentScreen);
    }

    /**
     * 用于处理横竖屏切换时，滚动到一半不再滚动的问题
     */
    public void onScreenChange(final int frameIndex) {
        if (mCurrentScreen < getChildCount() - 1) {
            this.post(new Runnable() {

                @Override
                public void run() {
                    // snapToScreenAnimate(mCurrentScreen);
                    setCurrentScreen(mCurrentScreen);
                }
            });
        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            viewLocked(true);
            int mScrollX = mScroller.getCurrX();
            int mScrollY = mScroller.getCurrY();
            this.scrollTo(mScrollX, mScrollY);
            postInvalidate();
        } else if (mNextScreen != INVALID_SCREEN) {
            int newScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
            if (mCurrentScreen != newScreen) {
                int oldIndex = mCurrentScreen;
                mCurrentScreen = newScreen;
                mNextScreen = INVALID_SCREEN;
                /**
                 * 检测当前view的边距是否和屏幕边距重合，如果不重合则继续滑动到重合的边距
                 */
                if (!checkScreenPosition(mCurrentScreen)) {
                    snapToScreenAnimate(mCurrentScreen);
                    return;
                }
                viewChanged(oldIndex, mCurrentScreen);
                clearChildrenCache();
            }
            viewLocked(mTouchState != TOUCH_STATE_REST);
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        // 这个变量有什么用？TODO
        boolean restore = false;
        boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN;
        // If we are not scrolling or flinging, draw only the current screen
        if (fastDraw) {
            drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());
            // Log.d(TAG, "dispatchDraw time A " + (t - System.currentTimeMillis()));
        } else {
            final long drawingTime = getDrawingTime();
            // If we are flinging, draw only the current screen and the target screen
            if (mNextScreen >= 0 && mNextScreen < getChildCount() && Math.abs(mCurrentScreen - mNextScreen) == 1) {
                drawChild(canvas, getChildAt(mCurrentScreen), drawingTime);
                drawChild(canvas, getChildAt(mNextScreen), drawingTime);
                // Log.d(TAG, "dispatchDraw time B " + (t - System.currentTimeMillis()));
            } else {
                // If we are scrolling, draw all of our children
                final int count = getChildCount();
                for (int i = 0; i < count; i++) {
                    drawChild(canvas, getChildAt(i), drawingTime);
                    // Log.d(TAG, "dispatchDraw time C" + i + " " + (t2 - System.currentTimeMillis()));
                }
                // Log.d(TAG, "dispatchDraw time C- " + (t - System.currentTimeMillis()));
            }
        }
        drawPageIndex(canvas);
        if (restore) {
            canvas.restore();
        }
    }

    protected void drawPageIndex(Canvas canvas) {
        if (drawPageIndex) {
            int count = this.getChildCount();
            if (count <= 1) {
                return;
            }
            if (pageIndex == null) {
                pageIndex = new PageIndex(this.getContext());
                pageIndex.setPosition(PageIndex.CENTER);
                pageIndex.setType(PageIndex.TYPE_RECT);
                pageIndex.setCurrentColor(Color.RED);
            }
            pageIndex.setCount(count);
            pageIndex.setCurrentIndex(getRealIndex(mCurrentScreen));
            int x = getScrollX();
            int y = (int) (getHeight() * 0.995);
            canvas.translate(x, y);
            pageIndex.draw(canvas);
            canvas.translate(-x, -y);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
        }
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
        }
        // The children are given the same width and height as the workspace
        final int count = getChildCount();
    	for (int i = 0; i < count; i++) {
    		getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
    	}
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int childLeft = 0;
        final int count = getChildCount();
        int width = getWindowWidth();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                // 注意：在布局时，不是以子构件的宽度来布局，而是以屏幕宽度来布局，切忌！！！！
                final int childWidth = width;
                // 加了广告SDK后，有时会报空指针错误
                try {
                    child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }

                childLeft += childWidth;
            }
        }
        if (mFirstLayout) {
            scrollTo(mCurrentScreen * width, 0);
            mFirstLayout = false;
        }
    }

    @Override
    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
        int screen = indexOfChild(child);
        if (screen != mCurrentScreen || !mScroller.isFinished()) {
            return true;
        }
        return false;
    }

    @Override
    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
        int focusableScreen;
        if (mNextScreen != INVALID_SCREEN) {
            focusableScreen = mNextScreen;
        } else {
            focusableScreen = mCurrentScreen;
        }
        // FIX BY DGD 这个方法什么时候被调用？ removeview之后调用到这里 会导致空指针异常
        // 加入芒果的广告后，viewgroup可能不为空，但是里面的child仍然可能为空，这里只能try一下，能够找到问题的根本所在更好
        View view = getChildAt(focusableScreen);
        try {
            if (view != null) {
                view.requestFocus(direction, previouslyFocusedRect);
            }
        } catch (Exception e) {
            Log.e(TAG, "onRequestFocusInDescendants", e);
        }
        return false;
    }

    @Override
    public boolean dispatchUnhandledMove(View focused, int direction) {
        if (direction == View.FOCUS_LEFT) {
            if (getCurrentScreen() > 0) {
                snapToScreenAnimate(getCurrentScreen() - 1);
                return true;
            }
        } else if (direction == View.FOCUS_RIGHT) {
            if (getCurrentScreen() < getChildCount() - 1) {
                snapToScreenAnimate(getCurrentScreen() + 1);
                return true;
            }
        }
        return super.dispatchUnhandledMove(focused, direction);
    }

    private static final int LONG_PRESS = 2;
    private boolean          isLongPress;
    private Handler          mHandler;
    private boolean          isMultiTouch;

    private class GestureHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case LONG_PRESS:
                isLongPress = true;
                break;
            default:
                throw new RuntimeException("Unknown message " + msg); // never
            }
        }
    }

    /**
     * 设置需要自己处理touchEvent事件的子组件
     * 
     * @param mInterceptTouchListener
     */
    public void setInterceptTouchListener(InterceptTouchListener mInterceptTouchListener) {
        this.mInterceptTouchListener = mInterceptTouchListener;
    }

    /**
     * 移除监听
     */
    public void removeInterceptTouchListener() {
        this.mInterceptTouchListener = null;
    }

    /**
     * 子组件是否需要自己处理touchEvent事件
     * 
     * @return
     */
    private boolean isChildInterceptTouchEvent(MotionEvent ev) {
        if (mInterceptTouchListener != null) {
            Log.d(TAG,
                    "ViewScroller_isChildInterceptTouchEvent:info=" + mInterceptTouchListener
                            .isNeedInterceptTouchEvent(ev));
            return mInterceptTouchListener.isNeedInterceptTouchEvent(ev);
        }
        return false;
    }



    /*@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mLocked) {
            return true;
        }
        final int action = ev.getAction();
        if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {
            return true;
        }
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(ev);
        final float x = ev.getX();
        final float y = ev.getY();
        switch (action & MotionEvent.ACTION_MASK) {
        // 多点触摸直接给子控件处理
        case MotionEvent.ACTION_POINTER_DOWN:
            isMultiTouch = true;
            return false;
        case MotionEvent.ACTION_POINTER_UP:
            isMultiTouch = false;
            return false;
        case MotionEvent.ACTION_MOVE:
            // 长按子控件处理
            if (isLongPress || isMultiTouch || isChildInterceptTouchEvent(ev)) {
                return false;
            }
            // 没有长按，也就是没有唤醒光标，不把move事件分发到子控件中，自己处理

            final int xDiff = (int) Math.abs(x - mLastMotionX);
            final int yDiff = (int) Math.abs(y - mLastMotionY);
            final int touchSlop = mTouchSlop;
            boolean xMoved = xDiff > touchSlop;
            boolean yMoved = yDiff > touchSlop;
            if ((xMoved || yMoved ) && !mLockScroll) {
                if (xMoved && xDiff > (yDiff * 2)) {
                    // Scroll if the user moved far enough along the X axis
                    mTouchState = TOUCH_STATE_SCROLLING;
                    viewLocked(true);
                    enableChildrenCache();
                }
                // Either way, cancel any pending longpress
                if (mAllowLongPress) {
                    mAllowLongPress = false;
                    // Try canceling the long press. It could also have been scheduled
                    // by a distant descendant, so use the mAllowLongPress flag to block
                    // everything
                    final View currentScreen = getChildAt(mCurrentScreen);
                    currentScreen.cancelLongPress();
                }
            }
            break;
        case MotionEvent.ACTION_DOWN:
            // Remember location of down touch
            mLastMotionX = x;
            mLastMotionY = y;
            isMultiTouch = false;
            mAllowLongPress = true;
            // 长按超时时间
            MotionEvent mCurrentDownEvent = MotionEvent.obtain(ev);
            isLongPress = false;
            mHandler.removeMessages(LONG_PRESS);
            // mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() + 600);
            Message msg = new Message();
            msg.what = LONG_PRESS;
            Bundle bundle = new Bundle();
            bundle.putFloat("RAWX", ev.getRawX());
            bundle.putFloat("RAWY", ev.getRawY());
            msg.setData(bundle);
            mHandler.sendMessageAtTime(msg, mCurrentDownEvent.getDownTime() + 200);
            *//*
             * If being flinged and user touches the screen, initiate drag; otherwise don't. mScroller.isFinished should
             * be false when being flinged.
             *//*
            mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (mVelocityTracker != null) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
            // Release the drag
            clearChildrenCache();
            mTouchState = TOUCH_STATE_REST;
            mAllowLongPress = false;
            viewLocked(false);
            break;
        }

        *//*
         * The only time we want to intercept motion events is if we are in the drag mode.
         *//*
        return mTouchState != TOUCH_STATE_REST;
    }*/

    protected void enableChildrenCache() {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final ViewGroup layout = (ViewGroup) getChildAt(i);
            layout.setAlwaysDrawnWithCacheEnabled(true);
            layout.setDrawingCacheEnabled(true);
        }
    }

    void clearChildrenCache() {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final ViewGroup layout = (ViewGroup) getChildAt(i);
            layout.setAlwaysDrawnWithCacheEnabled(false);
            layout.setDrawingCacheEnabled(false);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        float x = ev.getX();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:

                break;
            case MotionEvent.ACTION_MOVE:
                if (Math.abs(x - mLastMotionX) >= mTouchSlop) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        float x = ev.getX();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                // Remember where the motion event started
                mLastMotionX = x;
                break;
            case MotionEvent.ACTION_MOVE:

                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (mLocked) {
            return true;
        }
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(ev);
        final int action = ev.getAction();
        final float x = ev.getX();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            /*
             * If being flinged and user touches, stop the fling. isFinished will be false if being flinged.
             */
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
            // Remember where the motion event started
            mLastMotionX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            if (Math.abs(x - mLastMotionX) >= mTouchSlop) {
                mTouchState = TOUCH_STATE_SCROLLING;
            }
            if (mTouchState == TOUCH_STATE_SCROLLING) {
                // Scroll to follow the motion event
                final int deltaX = (int) (mLastMotionX - x);
                mLastMotionX = x;
                
                if (!canMoveInBoundry) {
                	if (deltaX < 0 && isInBoundry(true)) {
                		return true;
                	}
                	
                	if (deltaX > 0 && isInBoundry(false)) {
                		return true;
                	}
                }
                
                if (deltaX < 0) {
                    if (!isAbleMoveToRight()) {
                        return true;
                    }
                    
                    makeCycleShow(true);
                    if (getScrollX() > 0) {
                        scrollBy(Math.max(-getScrollX(), deltaX), 0);
                        viewLocked(true);
                    }
                } else if (deltaX > 0) {
                    if (!isAbleMoveToLeft()) {
                        return true;
                    }
                    
                    makeCycleShow(false);
                    final int availableToScroll = getChildAt(getChildCount() - 1).getRight() - getScrollX() - getWidth();
                    if (availableToScroll > 0) {
                        scrollBy(Math.min(availableToScroll, deltaX), 0);
                        viewLocked(true);
                    }
                }
            } else {
                viewLocked(false);
            }
            break;
        case MotionEvent.ACTION_UP:
            if (mTouchState == TOUCH_STATE_SCROLLING) {
                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000);
                int velocityX = (int) velocityTracker.getXVelocity();
                if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {
                    // Fling hard enough to move left
                    if (!isAbleMoveToRight()) {
                        return true;
                    }
                    snapToScreenAnimate(mCurrentScreen + 1);
                } else if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
                    // Fling hard enough to move right
                    if (!isAbleMoveToLeft()) {
                        return true;
                    }
                    snapToScreenAnimate(mCurrentScreen - 1);
                } else {
                    snapToDestination();
                }
                if (mVelocityTracker != null) {
                    mVelocityTracker.recycle();
                    mVelocityTracker = null;
                }
            } else {
                viewLocked(false);
            }
            mTouchState = TOUCH_STATE_REST;
            break;
        case MotionEvent.ACTION_CANCEL:
            viewLocked(false);
            mTouchState = TOUCH_STATE_REST;
        }

        return true;
    }
    
    /**
     * 判断当前是否在页面的边界
     * @param isFirst,参数如果为true则表示在第一屏，false表示最后一屏
     * @return
     */
    private boolean isInBoundry(boolean isFirst) {
    	if (isFirst) {
    		return mCurrentScreen == 0 && getScrollX() <= 0;
    	} else {
    		return (mCurrentScreen == getChildCount() - 1) && (getScrollX() >= getWidth() * mCurrentScreen);
    	}
    }

    private void makeCycleShow(boolean right) {
        if (right && isInBoundry(true)) {
            if (!mCycleShowed) {
                initViewIndexMap();
            }
            mCycleShowed = true;
            View view = this.getChildAt(0);
            this.removeView(view);
            this.addView(view);
            mCurrentScreen = this.getChildCount() - 1;
            scrollTo(mCurrentScreen * this.getWindowWidth(), 0);
            this.requestLayout();
        } else if (!right && isInBoundry(false)) {
            if (!mCycleShowed) {
                initViewIndexMap();
            }
            mCycleShowed = true;
            final int count = getChildCount();
            View view = this.getChildAt(count - 1);
            this.removeView(view);
            this.addView(view, 0);
            mCurrentScreen = 0;
            scrollTo(mCurrentScreen * this.getWindowWidth(), 0);
            this.requestLayout();
        }
    }

    protected void initViewIndexMap() {
        viewIndexMap.clear();
        int count = getChildCount();
        for (int i = count - 1; i >= 0; i--) {
            viewIndexMap.put(getChildAt(i), i);
        }
    }

    protected int getRealIndex(int view) {
        int i = view;
        if (mCycleShowed && viewIndexMap.size() > 0) {
            Integer index = viewIndexMap.get(getChildAt(view));
            if (index != null) {
                i = index.intValue();
            }
        }
        return i;
    }

    public int getScreenByIndex(int view) {
        int screen = view;
        if (mCycleShowed && viewIndexMap.size() > 0) {
            for (int i = getChildCount() - 1; i >= 0; i--) {
                View v = getChildAt(i);
                Integer index = viewIndexMap.get(v);
                if (index != null && view == index.intValue()) {
                    screen = i;
                    break;
                }
            }
        }
        return screen;
    }

    protected void snapToDestination() {
        final int screenWidth = getWidth();
        final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;
        snapToScreenAnimate(whichScreen);
    }

    public void setCurrentView(int view) {
        view = Math.max(0, Math.min(view, getChildCount() - 1));
        int whichScreen = getScreenByIndex(view);
        mNextScreen = INVALID_SCREEN;
        setCurrentScreen(whichScreen);
    }

    /**
     * 检测当前view的边距是否和屏幕边距重合
     * 
     * @param whichScreen
     */
    public boolean checkScreenPosition(int whichScreen) {
        boolean isCoincide = false;
        ;
        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        int width = getWindowWidth();
        final int newX = whichScreen * width;
        final int delta = newX - getScrollX();
        if (delta == 0) {
            isCoincide = true;
        }
        return isCoincide;
    }

    public void snapToScreenAnimate(int whichScreen) {
        int oldIndex = mCurrentScreen;
        visibleChanged(true);
        enableChildrenCache();
        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        boolean changingScreens = whichScreen != mCurrentScreen;
        mNextScreen = whichScreen;
        View focusedChild = getFocusedChild();
        if (focusedChild != null && changingScreens && focusedChild == getChildAt(mCurrentScreen)) {
            focusedChild.clearFocus();
        }
        notifyTabShouldChange(whichScreen);
        notifyPageChangeByScroll(oldIndex, getRealIndex(whichScreen));
        int width = getWindowWidth();
        final int newX = whichScreen * width;
        final int delta = newX - getScrollX();
        mScroller.startScroll(getScrollX(), 0, delta, 0, DURATION_BETWEEN_SCREEN);
        invalidate();
    }

    /**
     * get screen width
     * 
     * @return
     */
    protected int getWindowWidth() {
        int width = 0;
        DisplayMetrics displayMetrics = new DisplayMetrics();

        ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        width = displayMetrics.widthPixels;
        return width;
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        final SavedState state = new SavedState(super.onSaveInstanceState());
        state.currentScreen = mCurrentScreen;
        return state;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        if (savedState.currentScreen > -1) {
            int oldIndex = mCurrentScreen;
            mCurrentScreen = Math.max(0, Math.min(savedState.currentScreen, getChildCount() - 1));
            notifyTabShouldChange(mCurrentScreen);
            viewChanged(oldIndex, mCurrentScreen);
        }
    }

    public int getScreenForView(View v) {
        int result = -1;
        if (v != null) {
            ViewParent vp = v.getParent();
            int count = getChildCount();
            for (int i = 0; i < count; i++) {
                if (vp == getChildAt(i)) {
                    return i;
                }
            }
        }
        return result;
    }

    /**
     * Unlocks the SlidingDrawer so that touch events are processed.
     * 
     * @see #lock()
     */
    public void unlock() {
        mLocked = false;
    }

    /**
     * Locks the SlidingDrawer so that touch events are ignores.
     * 
     * @see #unlock()
     */
    public void lock() {
        mLocked = true;
    }

    public void lockScroll(){
        mLockScroll = true;
    }

    public void unLockScroll(){
        mLockScroll = false;
    }

    /**
     * @return True is long presses are still allowed for the current touch
     */
    public boolean allowLongPress() {
        return mAllowLongPress;
    }

    /**
     * Set true to allow long-press events to be triggered, usually checked by {@link } to accept or block
     * dpad-initiated long-presses.
     */
    public void setAllowLongPress(boolean allowLongPress) {
        mAllowLongPress = allowLongPress;
    }

    void moveToDefaultScreen() {
        snapToScreenAnimate(mDefaultScreen);
        getChildAt(mDefaultScreen).requestFocus();
    }

    protected void viewChanged(int oldIndex, int screen) {
        if (this.mViewChangeListener != null) {
            try {
                mViewChangeListener.onViewChange(oldIndex, getRealIndex(screen));
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 在切换view的时候，隐藏键盘
            hiddenSoftinput();
        }
        viewLocked(false);
    }

    protected void notifyTabShouldChange(int screen){
    	if(mViewChangeListener != null){
    		mViewChangeListener.onNotifyTabbarShouldChange(getRealIndex(screen));
    	}
    }
    
    public void visibleChanged(boolean flag) {
        if (this.mBarChangeVisibleListener != null) {
            try {
                mBarChangeVisibleListener.onBarVisible(flag);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    private void notifyPageChangeByScroll(int oldIndex, int witchIndex){
        if(mOnPageChangeByScroll != null){
            mOnPageChangeByScroll.onPageChangeByScroll(oldIndex, witchIndex);
        }
    }

    /**
     * 隐藏软键盘
     */
    private void hiddenSoftinput() {
        InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            imm.hideSoftInputFromWindow(this.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    protected void viewLocked(boolean locked) {
        if (this.mViewChangeListener != null) {
            mViewChangeListener.onViewLocked(locked);
        }
    }

    public void setViewChangeListener(OnViewChangeListener l) {
        mViewChangeListener = l;
    }

    public void setBarChangeVisibleListener(OnBarChangeVisibleListener l) {
        mBarChangeVisibleListener = l;
    }

    public void setOnPageChangeByScroll(OnPageChangeByScroll listener){
        mOnPageChangeByScroll = listener;
    }

    public void setDrawPageIndex(boolean drawPageIndex) {
        this.drawPageIndex = drawPageIndex;
    }

    @Override
    public void requestLayout() {
        super.requestLayout();
    }

    public static class SavedState extends BaseSavedState {

        int currentScreen = -1;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            currentScreen = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(currentScreen);
        }
    }

    /**
     * 
     * 描述：需要自己处理touchEvent的子组件，目前支持一个
     * 
     * @author zhanglei@myhexin.com
     */
    public interface InterceptTouchListener {

        public boolean isNeedInterceptTouchEvent(MotionEvent ev);
    }

}
